\title{myHDL Implementation of a CIC Filter} \author{Steven K Armour} \maketitle
In [1]:
    
import numpy as np
np.seterr(divide='ignore', invalid='ignore')
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
#import plotly.plotly as py
#import plotly.graph_objs as go
from sympy import *
from sympy import S; Zero=S.Zero
init_printing()
import scipy.signal as sig
%matplotlib notebook
import ipywidgets as widg
from myhdl import *
from myhdlpeek import Peeker
    
Christopher Felton who designed the original myHDL CIC filter found here https://github.com/jandecaluwe/site-myhdl-retired/blob/master/_ori/pages/projects/gciccomplete.txt
West Coast DSP blog article on CIC filters https://westcoastdsp.wordpress.com/2015/09/07/cascaded-integrator-comb-filters/
Target Architecture size
In [2]:
    
BitWidth=32
    
Code to read back the generated Verilog(VHDL)  from myHDL back into the Jupyter Notebook
In [3]:
    
#helper  functions to read in the .v and .vhd generated files into python
def VerilogTextReader(loc, printresult=True):
    with open(f'{loc}.v', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***Verilog modual from {loc}.v***\n\n', VerilogText)
    return VerilogText
def VHDLTextReader(loc, printresult=True):
    with open(f'{loc}.vhd', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***VHDL modual from {loc}.vhd***\n\n', VerilogText)
    return VerilogText
    
Z-Transform preliminary math and Z-Plane graphing code
In [4]:
    
z, r, DisAng=symbols('z, r, Omega')
zFunc=Eq(z, r*exp(1j*DisAng)); zFunc
    
    Out[4]:
In [5]:
    
zFuncN=lambdify((r, DisAng), zFunc.rhs, dummify=False)
zr=np.arange(-1.5, 1.5+.03, .03); zi=np.copy(zr)
zR, zI=np.meshgrid(zr, zi)
zN=zR+1j*zI
rN=1.0
AngThetaN=np.arange(0, 1+.005, .005)*2*np.pi
zAtR1=zFuncN(rN, AngThetaN)
    
In [6]:
    
%matplotlib notebook
def Zplot(zR, zI, HzNMag, HzAtR1NMag, HzNPhase, HzAtR1NPhase, title):
    
    
    fig = plt.figure()
    #plot the z space mag
    axZmag = fig.add_subplot(221, projection='3d')
    Mags=axZmag.plot_surface(zR, zI, HzNMag, cmap=plt.get_cmap('tab20'))
    axZmag.plot(np.real(zAtR1), np.imag(zAtR1), HzAtR1NMag, 'r-', label='r=1')
    axZmag.set_xlabel('Re'); axZmag.set_ylabel('Im'); axZmag.set_zlabel('Mag')
    axZmag.legend(loc='best')
    fig.colorbar(Mags)
    #plot the z space phase
    axZph = fig.add_subplot(222, projection='3d')
    Phase=axZph.plot_surface(zR, zI, HzNPhase, cmap=plt.get_cmap('tab20'))
    axZph.plot(np.real(zAtR1), np.imag(zAtR1), HzAtR1NPhase, 'r-', label='r=1')
    axZph.set_xlabel('Re'); axZph.set_ylabel('Im'); axZph.set_zlabel('Phase')
    axZph.legend(loc='best')
    fig.colorbar(Phase)
    axBodeM=fig.add_subplot(212)
    Mline=axBodeM.plot(AngThetaN, HzAtR1NMag, label='FTMag')
    axBodeM.set_ylabel('Mag')
    axBodeP=axBodeM.twinx()
    Pline=axBodeP.plot(AngThetaN, np.rad2deg(HzAtR1NPhase), 'g--', label='FTPhase')
    axBodeP.set_ylabel('Phase [deg]')
    axBodeP.set_xlabel('Ang')
    lns = Mline+Pline
    labs = [l.get_label() for l in lns]
    axBodeP.legend(lns, labs, loc='best')
    
    fig.suptitle(title)
    fig.show()
    
In [7]:
    
M=symbols('M')
DelayH=z**(-M); DelayH
    
    Out[7]:
In [8]:
    
DelaySupH=simplify(DelayH.subs(zFunc.lhs, zFunc.rhs)); DelaySupH
    
    Out[8]:
In [9]:
    
DelaySupH=simplify(DelaySupH.subs(r, 1)); DelaySupH
    
    Out[9]:
In [10]:
    
DelayHN=lambdify((z, M), DelayH, dummify=False)
Mvalue=2
HzN=DelayHN(zN, M=Mvalue); HzN.shape
HzNMag=np.abs(HzN); HzNPhase=np.angle(HzN)
HAtR1=zFuncN(rN, AngThetaN)
HzAtR1N=DelayHN(zAtR1, M=Mvalue)
HzAtR1NMag=np.abs(HzAtR1N); HzAtR1NPhase=np.angle(HzAtR1N)
    
In [11]:
    
def DelayExplorer(M=1):
    Mvalue=M
    
    HzN=DelayHN(zN, M=Mvalue); HzN.shape
    HzNMag=np.abs(HzN); HzNPhase=np.angle(HzN)
    HAtR1=zFuncN(rN, AngThetaN)
    HzAtR1N=DelayHN(zAtR1, M=Mvalue)
    HzAtR1NMag=np.abs(HzAtR1N); HzAtR1NPhase=np.angle(HzAtR1N)
    Zplot(zR, zI, HzNMag, HzAtR1NMag, HzNPhase, HzAtR1NPhase, 
          f'z Delay order M={M}')
    
In [12]:
    
# will add widgets for interative later
DelayExplorer(M=1)
    
    
    
In [13]:
    
def Delay(x, y, ena_in, clk):
    '''
        Z delay bulding block for a CIC filter
        
        Inputs:
            x (data): the x(n) data in feed
            ------------------------
            ena_in (bool): the exstiror calc hold input. calc is done only if 
            `ena_in` is True
            
            clk(bool): clock feed
            rst(bool): reset feed
        
        Outputs:
            y (data):  the y(n+1) output of y(n+1)=x(n)
            
    '''
    @always(clk. posedge)
    def logic():
        if ena_in:
            y.next=x
    return logic
    
In [14]:
    
Peeker.clear()
x=Signal(modbv(0)[BitWidth:]); Peeker(x, 'x')
y=Signal(modbv(0)[BitWidth:]); Peeker(y, 'y')
ena_in, clk=[Signal(bool(0)) for  _ in range(2)]
Peeker(ena_in, 'ena_in'); Peeker(clk, 'clk')
DUT=Delay(x, y, ena_in, clk)
DateCol=pd.DataFrame(columns=['x', 'y', 'ena_in'])
def Delay_TB():
    
    @always(delay(1))  ## delay in nano seconds
    def clkGen():
        clk.next = not clk
        
    @instance
    def stimulus():
        Tested_ena=False
        count=0
        while 1:
            
            if Tested_ena==False and count<=2:
                print(f'Tested_ena: {Tested_ena}, count:{count}')
            elif Tested_ena==False and count>2:
                print(f'Tested_ena: {Tested_ena}, count:{count}')
                ena_in.next=True
                Tested_ena=True
                x.next=0
           
            
            if Tested_ena  and count>2:
                x.next=x+1
            
            if count> 2*BitWidth:
                raise StopSimulation
            
            DateCol.loc[count]=[int(x),int(y), int(ena_in)]
            
            count+=1
            yield clk.posedge
                
                
            
    return instances()
sim = Simulation(DUT, Delay_TB(), *Peeker.instances()).run()
    
    
In [15]:
    
Peeker.to_wavedrom(start_time=0, stop_time=40, tock=True)
    
    
    
In [16]:
    
x=Signal(modbv(0)[BitWidth:])
y=Signal(modbv(0)[BitWidth:])
ena_in, clk=[Signal(bool(0)) for  _ in range(2)]
toVerilog(Delay, x, y, ena_in, clk)
VerilogTextReader('Delay');
    
    
In [17]:
    
CombH=1-z**(-M); CombH
    
    Out[17]:
In [18]:
    
CombSupH=simplify(CombH.subs(zFunc.lhs, zFunc.rhs)); CombSupH
    
    Out[18]:
In [19]:
    
CombSupH=simplify(CombSupH.subs(r, 1)); CombSupH
    
    Out[19]:
In [20]:
    
CombHN=lambdify((z, M), CombH, dummify=False)
def CombEx(M=2):
    Mvalue=M
    HzN=CombHN(zN, M=Mvalue); HzN.shape
    HzNMag=np.abs(HzN); HzNPhase=np.angle(HzN)
    HAtR1=zFuncN(rN, AngThetaN)
    HzAtR1N=DelayHN(zAtR1, M=Mvalue)
    HzAtR1NMag=np.abs(HzAtR1N); HzAtR1NPhase=np.angle(HzAtR1N)
    Zplot(zR, zI, HzNMag, HzAtR1NMag, HzNPhase, HzAtR1NPhase, 
          f'Comb of Order M={Mvalue}')
CombEx(M=2)
    
    
    
In [21]:
    
def Comb(x, y, ena_in, ena_out, clk, rst, M=2):
    '''
        the comb section of  a CIC filter relaying on `Delay` to create
        the Z dealy blocks
        
        Inputs:
            x (data): the x(n) data in feed
            ------------------------
            ena_in (bool): the exstiror calc hold input. calc is done only if 
            `ena_in` is True
            
            clk(bool): clock feed
            rst(bool): reset feed
        
        Outputs:
            y (data):  the y(n) output of y(n)=y(n-1)+x(n)
            ----------------------
            ena_out: the exstior calc hold output. will be false if 
            `ena_in` is False
        Parm:
            M: the nuumber of Z delays for this comb section
    '''
    
    
    #stage the the Zdelays
    Zdelay_i=[None for i in range(M)]
    
    #Parmters for sizeing the 2's comp interdaley wires
    WordLen_1=len(x)-1
    WireGuage=2**WordLen_1
    
    # Create the wiring between the delays
    Zwire_ij=[Signal(modbv(0, min=-WireGuage, max=WireGuage)) for j in range(M)]
    #instainsate and wire togather the Zdelays
    for i in range(M):
        if i==0:
            Zdelay_i[i]=Delay(x, Zwire_ij[i], ena_in, clk)
        else:
            Zdelay_i[i]=Delay(Zwire_ij[i-1], Zwire_ij[i], ena_in, clk)
    
    #make the last delay output unieq x(M-1)
    subx=Zwire_ij[M-1]
    
    @always(clk.posedge)
    def logc():
        if rst:
            y.next=0
        else:
            if ena_in:
                #y=x-x(M-1)
                y.next=x-subx
                ena_out.next=True
            else:
                ena_out.next=False
    return instances()
    
In [22]:
    
Peeker.clear()
x=Signal(modbv(1)[BitWidth:]); Peeker(x, 'x')
y=Signal(modbv(5)[BitWidth:]); Peeker(y, 'y')
ena_in, ena_out, clk, rst=[Signal(bool(0)) for  _ in range(4)]
Peeker(ena_in, 'ena_in'); Peeker(ena_out, 'ena_out'); Peeker(clk, 'clk'); Peeker(rst, 'rst')
DUT=Comb(x, y, ena_in, ena_out, clk, rst, M=2)
def Comb_TB():
    
    @always(delay(1))  ## delay in nano seconds
    def clkGen():
        clk.next = not clk
        
    @instance
    def stimulus():
        Tested_ena=False
        Tested_rst=False
        count=0
        while 1:
            
            if Tested_ena==False and count<=2:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
            elif Tested_ena==False and count>2:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
                ena_in.next=True
                Tested_ena=True
            
            if Tested_ena and Tested_rst==False:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
                rst.next=True
                Tested_rst=True
            elif Tested_ena and Tested_rst and  count<=4:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
                rst.next=False
                Tested_rst=True
                x.next=1
            
            if Tested_ena and Tested_rst and count>4:
                x.next=2*(x+1)
            
            if count> 2*BitWidth:
                raise StopSimulation
            count+=1
            yield clk.posedge
                
                
            
    return instances()
sim = Simulation(DUT, Comb_TB(), *Peeker.instances()).run()
    
    
In [23]:
    
Peeker.to_wavedrom(start_time=0, stop_time=40, tock=True)
    
    
    
In [24]:
    
x=Signal(modbv(1)[BitWidth:])
y=Signal(modbv(5)[BitWidth:])
ena_in, ena_out, clk, rst=[Signal(bool(0)) for  _ in range(4)]
toVerilog(Comb, x, y, ena_in, ena_out, clk, rst, M=2)
VerilogTextReader('Comb');
    
    
In [25]:
    
IntegratorH=1/(1-z**-1); IntegratorH
    
    Out[25]:
In [26]:
    
IntegratorSupH=simplify(IntegratorH.subs(zFunc.lhs, zFunc.rhs))
IntegratorSupH
    
    Out[26]:
In [27]:
    
IntegratorSupH=simplify(IntegratorSupH.subs(r, 1))
IntegratorSupH
    
    Out[27]:
In [28]:
    
IntegratorHN=lambdify(z, IntegratorH, dummify=False)
HzN=IntegratorHN(zN); HzN.shape
HzNMag=np.abs(HzN); HzNPhase=np.angle(HzN)
HAtR1=zFuncN(rN, AngThetaN)
HzAtR1N=IntegratorHN(zAtR1)
HzAtR1NMag=np.abs(HzAtR1N); HzAtR1NPhase=np.angle(HzAtR1N)
Zplot(zR, zI, HzNMag, HzAtR1NMag, HzNPhase, HzAtR1NPhase, 'Integrator')
    
    
    
In [29]:
    
def Integrator(x, y, ena_in, ena_out, clk, rst):
    '''
        Simple Integrator/ Accumultor with exstior hold contorls as part
        of the building blocks of a CIC filter
        
        Inputs:
            x (data): the x(n) data in feed
            ------------------------
            ena_in (bool): the exstiror calc hold input. calc is done only if 
            `ena_in` is True
            
            clk(bool): clock feed
            rst(bool): reset feed
        
        Outputs:
            y (data):  the y(n) output of y(n)=y(n-1)+x(n)
            ----------------------
            ena_out: the exstior calc hold output. will be false if 
            `ena_in` is False
    '''
    @always(clk.posedge)
    def logic():
        if rst:
            y.next=0
        else:
            if ena_in:
                #y(n)=y(n-1)+x(n)
                y.next=y+x
                ena_out.next=True
            else:
                ena_out.next=False
    
    return logic
    
In [30]:
    
Peeker.clear()
x=Signal(modbv(1)[BitWidth:]); Peeker(x, 'x')
y=Signal(modbv(5)[BitWidth:]); Peeker(y, 'y')
ena_in, ena_out, clk, rst=[Signal(bool(0)) for  _ in range(4)]
Peeker(ena_in, 'ena_in'); Peeker(ena_out, 'ena_out'); Peeker(clk, 'clk'); Peeker(rst, 'rst')
DUT=Integrator(x, y, ena_in, ena_out, clk, rst)
def Integrator_TB():
    
    @always(delay(1))  ## delay in nano seconds
    def clkGen():
        clk.next = not clk
        
    @instance
    def stimulus():
        Tested_ena=False
        Tested_rst=False
        count=0
        while 1:
            
            if Tested_ena==False and count<=2:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
            elif Tested_ena==False and count>2:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
                ena_in.next=True
                Tested_ena=True
            
            if Tested_ena and Tested_rst==False:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
                rst.next=True
                Tested_rst=True
            elif Tested_ena and Tested_rst and  count<=4:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
                rst.next=False
                Tested_rst=True
                x.next=0
            
            if Tested_ena and Tested_rst and count>4:
                x.next=x+1
            
            if count> 2*BitWidth:
                raise StopSimulation
            count+=1
            yield clk.posedge
                
                
            
    return instances()
sim = Simulation(DUT, Integrator_TB(), *Peeker.instances()).run()
    
    
In [31]:
    
Peeker.to_wavedrom(start_time=0, stop_time=40, tock=True)
    
    
    
In [32]:
    
x=Signal(modbv(1)[BitWidth:])
y=Signal(modbv(5)[BitWidth:])
ena_in, ena_out, clk, rst=[Signal(bool(0)) for  _ in range(4)]
toVerilog(Integrator, x, y, ena_in, ena_out, clk, rst)
VerilogTextReader('Integrator');
    
    
    
In [33]:
    
R, k=symbols('R, k')
X=Function('X')(z); X
    
    Out[33]:
In [34]:
    
Decimator=summation(X.subs(z, z**(1/R) *exp(2j*pi*k/R)), (k, 0, R-1))/R
Decimator
    
    Out[34]:
In [35]:
    
Decimator=simplify(Decimator.subs(zFunc.lhs, zFunc.rhs))
Decimator
    
    Out[35]:
In [36]:
    
Decimator.subs(r, 1)
    
    Out[36]:
In [37]:
    
def Decimator(x, y, ena_in, ena_out, clk, rst, R=8):
    '''
        A decimation (down sampling) section for a CIC filter
        
        Inputs:
            x (data): the x(n) data in feed
            ------------------------
            ena_in (bool): the exstiror calc hold input. calc is done only if 
            `ena_in` is True
            
            clk(bool): clock feed
            rst(bool): reset feed
        
        Outputs:
            y (data):  the y(n) output 
            ----------------------
            ena_out: the exstior calc hold output. will be false if 
            `ena_in` is False
        Parm:
            R: the decimation ratio
    '''
    countSize=2**np.ceil(np.log2(R))
    count=Signal(intbv(0, max=countSize, min=0))
    
    @always(clk.posedge)
    def PassControl():
        if rst:
            y.next=0
        else:
            if count==0:
                y.next=x
                ena_out.next=True
            else:
                y.next=0
                ena_out.next=False
        
    @always(clk.posedge)
    def CountControl():
        if rst:
            count.next=0
        else:
            if count==R-1:
                count.next=0
            else:
                count.next=count+1
    
    return instances()
    
In [38]:
    
Peeker.clear()
x=Signal(modbv(1)[BitWidth:]); Peeker(x, 'x')
y=Signal(modbv(0)[BitWidth:]); Peeker(y, 'y')
ena_in, ena_out, clk, rst=[Signal(bool(0)) for  _ in range(4)]
Peeker(ena_in, 'ena_in'); Peeker(ena_out, 'ena_out'); Peeker(clk, 'clk'); Peeker(rst, 'rst')
DUT=Decimator(x, y, ena_in, ena_out, clk, rst, R=2)
def Integrator_TB():
    
    @always(delay(1))  ## delay in nano seconds
    def clkGen():
        clk.next = not clk
        
    @instance
    def stimulus():
        Tested_ena=False
        Tested_rst=False
        count=0
        while 1:
            
            if Tested_ena==False and count<=2:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
            elif Tested_ena==False and count>2:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
                ena_in.next=True
                Tested_ena=True
            
            if Tested_ena and Tested_rst==False:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
                rst.next=True
                Tested_rst=True
            elif Tested_ena and Tested_rst and  count<=4:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
                rst.next=False
                Tested_rst=True
                x.next=1
            
            if Tested_ena and Tested_rst and count>4:
                x.next=x+1
            
            if count> 2*BitWidth:
                raise StopSimulation
            count+=1
            yield clk.posedge
                
                
            
    return instances()
sim = Simulation(DUT, Integrator_TB(), *Peeker.instances()).run()
    
    
In [39]:
    
Peeker.to_wavedrom(start_time=0, stop_time=40, tock=True)
    
    
    
In [40]:
    
x=Signal(modbv(1)[BitWidth:])
y=Signal(modbv(0)[BitWidth:])
ena_in, ena_out, clk, rst=[Signal(bool(0)) for  _ in range(4)]
toVerilog(Decimator, x, y, ena_in, ena_out, clk, rst, R=2)
VerilogTextReader('Decimator');
    
    
    
In [41]:
    
InterpolatorTheory=X.subs(z, exp(1j*DisAng*R)); InterpolatorTheory
    
    Out[41]:
In [42]:
    
def Interpolator(x, y, ena_in, ena_out,  clk, rst, R=8):
    '''
        A interpolation section for a CIC filter
        
        Inputs:
            x (data): the x(n) data in feed
            ------------------------
            ena_in (bool): the exstiror calc hold input. calc is done only if 
            `ena_in` is True
            
            clk(bool): clock feed
            rst(bool): reset feed
        
        Outputs:
            y (data):  the y(n) output of y(n)=y(n-1)+x(n)
            ----------------------
            ena_out: the exstior calc hold output. will be false if 
            `ena_in` is False
        Parm:
            R: the up-sampleing ratio
    '''
    countSize=2**np.ceil(np.log2(R))
    count=Signal(intbv(0, max=countSize, min=0))
    
    @always(clk.posedge)
    def PassControl():
        if rst:
            y.next=0
        else:
            if ena_in:
                y.next=x
                ena_out.next=True
            
            elif count>0:
                y.next=0
                ena_out.next=True
            
            else:
                y.next=0
                ena_out.next=False
        
        
    @always(clk.posedge)
    def CountControl():
        if rst:
            count.next=0
        else:
            if ena_in:
                count.next=R-1
            elif count>0:
                count.next=count+1
    
    
    
    return instances()
    
In [43]:
    
Peeker.clear()
x=Signal(modbv(1)[BitWidth:]); Peeker(x, 'x')
y=Signal(modbv(0)[BitWidth:]); Peeker(y, 'y')
ena_in, ena_out, clk, rst=[Signal(bool(0)) for  _ in range(4)]
Peeker(ena_in, 'ena_in'); Peeker(ena_out, 'ena_out'); Peeker(clk, 'clk'); Peeker(rst, 'rst')
DUT=Interpolator(x, y, ena_in, ena_out, clk, rst, R=2)
def Integrator_TB():
    
    @always(delay(1))  ## delay in nano seconds
    def clkGen():
        clk.next = not clk
        
    @instance
    def stimulus():
        Tested_ena=False
        Tested_rst=False
        count=0
        while 1:
            
            if Tested_ena==False and count<=2:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
            elif Tested_ena==False and count>2:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
                ena_in.next=True
                Tested_ena=True
            
            if Tested_ena and Tested_rst==False:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
                rst.next=True
                Tested_rst=True
            elif Tested_ena and Tested_rst and  count<=4:
                print(f'Tested_ena: {Tested_ena}, Tested_rst:{Tested_rst}, count:{count}')
                rst.next=False
                Tested_rst=True
                x.next=1
            
            if Tested_ena and Tested_rst and count>4:
                x.next=x+1
            
            if count> 2*BitWidth:
                raise StopSimulation
            count+=1
            yield clk.posedge
                
                
            
    return instances()
sim = Simulation(DUT, Integrator_TB(), *Peeker.instances()).run()
    
    
In [44]:
    
Peeker.to_wavedrom(start_time=0, stop_time=40, tock=True)
    
    
    
In [45]:
    
x=Signal(modbv(1)[BitWidth:])
y=Signal(modbv(0)[BitWidth:])
ena_in, ena_out, clk, rst=[Signal(bool(0)) for  _ in range(4)]
toVerilog(Interpolator, x, y, ena_in, ena_out, clk, rst, R=2)
VerilogTextReader('Interpolator');
    
    
In [46]:
    
def PassThrough(x, y, ena_in, ena_out):
    '''
        A pass-throug (do nothing) section for a CIC filter
        
        Inputs:
            x (data): the x(n) data in feed
            ------------------------
            ena_in (bool): the exstiror calc hold input. calc is done only if 
            `ena_in` is True
        
        Outputs:
            y (data):  the y(n) output of y(n)=y(n-1)+x(n)
            ----------------------
            ena_out: the exstior calc hold output. will be false if 
            `ena_in` is False
    '''
    @always_comb
    def logic():
        y.next=x
        ena_out.next=ena_in
    return logic
    
In [47]:
    
Peeker.clear()
x=Signal(modbv(1)[BitWidth:]); Peeker(x, 'x')
y=Signal(modbv(0)[BitWidth:]); Peeker(y, 'y')
ena_in, ena_out, clk=[Signal(bool(0)) for  _ in range(3)]
Peeker(ena_in, 'ena_in'); Peeker(ena_out, 'ena_out'); Peeker(clk, 'clk')
DUT=PassThrough(x, y, ena_in, ena_out)
def Integrator_TB():
    
    @always(delay(1))  ## delay in nano seconds
    def clkGen():
        clk.next = not clk
        
    @instance
    def stimulus():
        count=0
        while 1:
            if count<=5:
                ena_in.next=True
            elif count<=10:
                ena_in.next=False
            elif count>=15:
                ena_in.next=True
            
            if count> 2*BitWidth:
                raise StopSimulation
            x.next=x+1
            count+=1
            yield clk.posedge
                
                
            
    return instances()
sim = Simulation(DUT, Integrator_TB(), *Peeker.instances()).run()
    
In [48]:
    
Peeker.to_wavedrom(start_time=0, stop_time=40, tock=True)
    
    
    
In [49]:
    
x=Signal(modbv(1)[BitWidth:])
y=Signal(modbv(0)[BitWidth:])
ena_in, ena_out, clk=[Signal(bool(0)) for  _ in range(3)]
toVerilog(PassThrough, x, y, ena_in, ena_out)
VerilogTextReader('PassThrough');
    
    
In [50]:
    
N=symbols('N')
CIC=simplify(((1-z**(-R*M))**N)/((1-z**(-1))**N)); CIC
    
    Out[50]:
In [51]:
    
CICsub=simplify(CIC.subs(zFunc.lhs, zFunc.rhs)); CICsub
    
    Out[51]:
In [52]:
    
CICN=lambdify((z, M, R, N), CIC, dummify=False)
def CICEx(N=2, M=2, R=2):
    Mvalue=M; Rvalue=R; Nvalue=N
    HzN=CICN(zN, M=Mvalue, R=Rvalue, N=Nvalue); HzN.shape
    HzNMag=np.abs(HzN); HzNPhase=np.angle(HzN)
    HAtR1=zFuncN(rN, AngThetaN)
    HzAtR1N=CICN(zAtR1, M=Mvalue, R=Rvalue, N=Nvalue)
    HzAtR1NMag=np.abs(HzAtR1N); HzAtR1NPhase=np.angle(HzAtR1N)
    Zplot(zR, zI, HzNMag, HzAtR1NMag, HzNPhase, HzAtR1NPhase, 
         f'CIC Dec of N={Nvalue}, M={Mvalue}, R={Rvalue}')
CICEx()
    
    
    
In [53]:
    
def CICFilter(x, y, ena_in, ena_out, clk, rst, N=3, M=2, R=8, Type=None):
    '''
        The complet CIC filter
        
        Inputs:
            x (data): the x(n) data in feed
            ------------------------
            ena_in (bool): the exstiror calc hold input. calc is done only if 
            `ena_in` is True
            
            clk(bool): clock feed
            rst(bool): reset feed
        
        Outputs:
            y (data):  the y(n) output of y(n)=y(n-1)+x(n)
            ----------------------
            ena_out: the exstior calc hold output. will be false if 
            `ena_in` is False
        Parm:
            N: the number of stages
            M: the Z delay order
            R: the decimation/Interpolation ratio
            Type (None, 'Dec', 'Interp'): type of CIC filter
    '''
    #Parmters for sizeing the 2's comp data wires
    #assumes len(x)==len(y)
    WordLen_1=len(x)-1
    WireGuage=2**WordLen_1
    
    
    
    #------------------------------------------------
    #create the wires from the interpoltor (or lack of) to the comb sec
    #data wire
    Interp_Comb_DWire=Signal(intbv(0, min=-WireGuage, max=WireGuage))
    #enable wire
    Interp_Comp_EWire=Signal(bool(0))
    
    #instatiniat the interpolator (or lack of)
    if Type=='Interp':
        #                   x, y,                 ena_in, ena_out,       clk, rst, R
        Interp=Interpolator(x, Interp_Comb_DWire, ena_in, Interp_Comp_EWire, clk, rst, R)
    else:
                          #x, y, ena_in, ena_out  
        Interp=PassThrough(x, Interp_Comb_DWire, ena_in, Interp_Comp_EWire)
    
    #------------------------------------------------------------
    
    #Data Wires
    Comb_DWireIJ=[Signal(intbv(0, min=-WireGuage, max=WireGuage)) for i in range(N)]
    #Enable Wires
    Comb_EWireIJ=[Signal(bool(0)) for i in range(N)]
    
    #instatintte the comb sections and wire them
    Comb_i=[]
    for i in range(N):
        if i==0:
            #                  x,                 y,                ena_in,            ena_out, clk, rst, M
            Comb_i.append(Comb(Interp_Comb_DWire, Comb_DWireIJ[i] , Interp_Comp_EWire, Comb_EWireIJ[i], clk, rst, M))
        else:
            #                  x,                 y,               ena_in,            ena_out,         clk, rst, M
            Comb_i.append(Comb(Comb_DWireIJ[i-1], Comb_DWireIJ[i], Comb_EWireIJ[i-1], Comb_EWireIJ[i], clk, rst, M))
    
    
    #------------------------------------------------------------
    #Data Wires
    Integrator_DWireIJ=[Signal(intbv(0, min=-WireGuage, max=WireGuage)) for i in range(N)]
    #Enable Wires
    Integrator_EWireIJ=[Signal(bool(0)) for i in range(N)]
    #instatintte the integrator sections and wire them
    Integrtor_i=[]
    for i in range(N):
        if i==0:
            #                             x,                 y,                     ena_in, ena_out,               clk, rst
            Integrtor_i.append(Integrator(Comb_DWireIJ[N-1], Integrator_DWireIJ[i], Comb_EWireIJ[N-1], Integrator_EWireIJ[i], clk, rst))
        else:
            #                             x,                       y,                     ena_in,                  ena_out,               clk, rst
            Integrtor_i.append(Integrator(Integrator_DWireIJ[i-1], Integrator_DWireIJ[i], Integrator_EWireIJ[i-1], Integrator_EWireIJ[i], clk, rst))
    
    
    #-------------------------------------------------------------
    #instatiniat the decimator (or lack of)
    if Type == 'Dec':
        #             x,                       y, ena_in,                  ena_out, clk, rst, R
        Dec=Decimator(Integrator_DWireIJ[N-1], y, Integrator_EWireIJ[N-1], ena_out, clk, rst, R)
    else:
        #               x,                       y, ena_in,                  ena_out
        Dec=PassThrough(Integrator_DWireIJ[N-1], y, Integrator_EWireIJ[N-1], ena_out)
    
    return instances()
    
In [54]:
    
x=Signal(modbv(1)[BitWidth:])
y=Signal(modbv(0)[BitWidth:])
ena_in, ena_out, clk, rst=[Signal(bool(0)) for  _ in range(4)]
toVerilog(CICFilter, x, y, ena_in, ena_out, clk, rst, N=3, M=2, R=8, Type=None)
VerilogTextReader('CICFilter');